<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Transparency</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="cairo, graphics, C, 2D vector library, transparency">
<meta name="description" content="In this part of the Cairo graphics tutorial,
we will work with transparency.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Transparency</h1>

<p>
In this part of the Cairo C API tutorial, we will talk about transparency. 
We will provide some basic definitions and
two interesting transparency effects.
</p>

<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* NewSquare */
google_ad_slot = "0364418177";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script>

<p>
Transparency is the quality of being able to see through a material. 
The easiest way to understand transparency is to imagine a piece of glass or water. 
Technically, the rays of light can go through the glass and this way we 
can see objects behind the glass. 
</p>

<p>
In computer graphics, we can achieve transparency effects using <b>alpha compositing</b>.
Alpha compositing is the process of combining an image with a 
background to create the appearance of partial transparency. 

The composition process uses an <b>alpha channel</b>.
Alpha channel is an 8-bit layer in a graphics file format that is used for 
expressing translucency (transparency). The extra eight bits per pixel 
serves as a mask and represents 256 levels of translucency. 
<br>(answers.com, wikipedia.org)
</p>


<h2>Transparent rectangles</h2>

<p>
The first example will draw ten rectangles with different levels of transparency.
</p>

<pre class="code">
static void do_drawing(cairo_t *cr)
{
  gint i;
  for ( i = 1; i &lt;= 10; i++) {
      cairo_set_source_rgba(cr, 0, 0, 1, i*0.1);
      cairo_rectangle(cr, 50*i, 20, 40, 40);
      cairo_fill(cr);  
  }      
}
</pre>

<p>
The <code>cairo_set_source_rgba()</code> has an optional alpha 
parameter to provide transparency. This code creates ten rectangles 
with alpha values from 0.1 ... 1. 
</p>

<img src="/img/gfx/cairoc/rectangles.png" alt="Transparency">
<div class="figure">Figure: Transparency</div>


<h2>Puff effect</h2>

<p>
In the following example, we create a puff effect. The example will display a 
growing centered text that will gradually fade out from some point. This is 
a very common effect which we can often see in flash animations. 
The <code>cairo_paint_with_alpha()</code> method is crucial to create the effect.
</p>


<pre class="code">
#include &lt;cairo.h&gt;
#include &lt;gtk/gtk.h&gt;

void do_drawing(cairo_t *, GtkWidget *);

struct {
  gboolean timer; 
  gdouble alpha;
  gdouble size;
} glob;

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, 
    gpointer user_data)
{      
  cr = gdk_cairo_create(gtk_widget_get_window(widget)); 
  do_drawing(cr, widget);
  cairo_destroy(cr);

  return FALSE;
}

void do_drawing(cairo_t *cr, GtkWidget *widget)
{
  cairo_text_extents_t extents;

  GtkWidget *win = gtk_widget_get_toplevel(widget);
  
  gint width, height;
  gtk_window_get_size(GTK_WINDOW(win), &amp;width, &amp;height);  
  
  gint x = width/2;
  gint y = height/2;
  
  cairo_set_source_rgb(cr, 0.5, 0, 0); 
  cairo_paint(cr);   

  cairo_select_font_face(cr, "Courier",
      CAIRO_FONT_SLANT_NORMAL,
      CAIRO_FONT_WEIGHT_BOLD);
 
  glob.size += 0.8;

  if (glob.size > 20) {
      glob.alpha -= 0.01;
  }

  cairo_set_font_size(cr, glob.size);
  cairo_set_source_rgb(cr, 1, 1, 1); 

  cairo_text_extents(cr, "ZetCode", &amp;extents);
  cairo_move_to(cr, x - extents.width/2, y);
  cairo_text_path(cr, "ZetCode");
  cairo_clip(cr);

  cairo_paint_with_alpha(cr, glob.alpha);
  
  if (glob.alpha &lt;= 0) {
      glob.timer = FALSE;
  }     
}

static gboolean time_handler(GtkWidget *widget)
{ 
  if (!glob.timer) return FALSE;
  gtk_widget_queue_draw(widget);

  return TRUE;
}


int main(int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *darea;  
  
  glob.timer = TRUE;
  glob.alpha = 1.0;
  glob.size = 1.0;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  darea = gtk_drawing_area_new();
  gtk_container_add(GTK_CONTAINER (window), darea);

  g_signal_connect(G_OBJECT(darea), "draw", 
      G_CALLBACK(on_draw_event), NULL); 
  g_signal_connect(window, "destroy",
      G_CALLBACK(gtk_main_quit), NULL);
 
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 350, 200); 
  gtk_window_set_title(GTK_WINDOW(window), "Puff");

  g_timeout_add(14, (GSourceFunc) time_handler, (gpointer) window);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
</pre>

<p>
The example creates a growing and fading text on the window.
</p>

<pre class="explanation">
struct {
  gboolean timer; 
  gdouble alpha;
  gdouble size;
} glob; 
</pre>

<p>
Here we define some variables inside a structure. This is used to avoid
using globals.
</p>

<pre class="explanation">
draw_text(cr, widget); 
</pre>

<p>
The actual drawing of the text is delegated to the draw_text() 
function.
</p>

<pre class="explanation">
GtkWidget *win = gtk_widget_get_toplevel(widget);

gint width, height;
gtk_window_get_size(GTK_WINDOW(win), &amp;width, &amp;height);  

gint x = width/2;
gint y = height/2;
</pre>

<p>
The text is going to be centered on the window. Therefore we need
to find out the size of the parent widget.
</p>

<pre class="explanation">
cairo_set_source_rgb(cr, 0.5, 0, 0); 
cairo_paint(cr); 
</pre>

<p>
The background of the window is filled with some dark red colour.
</p>

<pre class="explanation">
cairo_select_font_face(cr, "Courier",
    CAIRO_FONT_SLANT_NORMAL,
    CAIRO_FONT_WEIGHT_BOLD);
</pre>

<p>
The text is going to be in Courier bold font.
</p>

<pre class="explanation">
glob.size += 0.8;

if (glob.size > 20) {
    glob.alpha -= 0.01;
}
</pre>

<p>
The size of the text is increased by 0.8 units. After it has reached
20 units, the alpha value starts decreasing. And the text fades away slowly.
</p>

<pre class="explanation">
cairo_text_extents(cr, "ZetCode", &amp;extents);
cairo_move_to(cr, x - extents.width/2, y);
</pre>

<p>
We get the text metrics. We will use only the text width. We move to a position 
where the text will be centered on the window.
</p>

<pre class="explanation">
cairo_text_path(cr, "ZetCode");
cairo_clip(cr);

cairo_paint_with_alpha(cr, glob.alpha);
</pre>

<p>
We get the path of the text with the <code>cairo_text_path()</code> method. We restrict 
the painting to the current path using the <code>cairo_clip()</code> method. 
The <code>cairo_paint_with_alpha()</code> method paints the current source everywhere within the
 current clip region using a mask of the alpha value.
</p>

<pre class="explanation">
glob.timer = TRUE;
glob.alpha = 1.0;
glob.size = 1.0;
</pre>

<p>
We initiate three variables.
</p>

<pre class="explanation">
static gboolean time_handler(GtkWidget *widget)
{
  if (!glob.timer) return FALSE;

  gtk_widget_queue_draw(widget);

  return TRUE;
}
</pre>

<p>
The main function of the <code>time_handler</code> call is to 
redraw the window regularly. When the function returns FALSE, the timeout 
function will cease to work.
</p>

<pre class="explanation">
g_timeout_add(14, (GSourceFunc) time_handler, (gpointer) window);
</pre>

<p>
We create a timer function. This function will call <code>time_handler</code> every 14 ms. 
</p>


<img src="/img/gfx/cairoc/puff.png" alt="Puff effect">
<div class="figure">Figure: Puff effect</div>


<h2>Waiting demo</h2>

<p>
In this examle, we use transparency effect to create a waiting demo. 
We will draw 8 lines that will gradually fade out creating an illusion, 
that a line is moving. Such effects are often used to inform users, that a 
lengthy task is going on behind the scenes. An example is streaming 
video over the internet.
</p>


<pre class="code">
#include &lt;cairo.h&gt;
#include &lt;gtk/gtk.h&gt;
#include &lt;math.h&gt;

static void do_drawing(cairo_t *, GtkWidget *);

struct {
  gushort count;
} glob;

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, 
    gpointer user_data)
{      
  cr = gdk_cairo_create(gtk_widget_get_window(widget));
  do_drawing(cr, widget);
  cairo_destroy(cr);

  return FALSE;
}

static void do_drawing(cairo_t *cr, GtkWidget *widget)
{  
  static gdouble const trs[8][8] = {
      { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
      { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
      { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
      { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65},
      { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
      { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
      { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
      { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, }
  };

  GtkWidget *win = gtk_widget_get_toplevel(widget);
  
  gint width, height;
  gtk_window_get_size(GTK_WINDOW(win), &amp;width, &amp;height);

  cairo_translate(cr, width/2, height/2);

  gint i = 0;
  for (i = 0; i &lt; 8; i++) {
      cairo_set_line_width(cr, 3);
      cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
      cairo_set_source_rgba(cr, 0, 0, 0, trs[glob.count%8][i]);

      cairo_move_to(cr, 0.0, -10.0);
      cairo_line_to(cr, 0.0, -40.0);
      cairo_rotate(cr, M_PI/4);

      cairo_stroke(cr);
  }   
}

static gboolean time_handler(GtkWidget *widget)
{
  glob.count += 1;
  gtk_widget_queue_draw(widget);
  
  return TRUE;
}

int main(int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *darea;  
  
  glob.count = 0;

  gtk_init(&amp;argc, &amp;argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  darea = gtk_drawing_area_new();
  gtk_container_add(GTK_CONTAINER (window), darea);

  g_signal_connect(G_OBJECT(darea), "draw", 
      G_CALLBACK(on_draw_event), NULL);  
  g_signal_connect(G_OBJECT(window), "destroy",
      G_CALLBACK(gtk_main_quit), NULL);

  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 150); 
  gtk_window_set_title(GTK_WINDOW(window), "Waiting demo");

  g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
  gtk_widget_show_all(window);  

  gtk_main();

  return 0;
}
</pre>

<p>
We draw eight lines with eight different alpha values.
</p>

<pre class="explanation">
 static gdouble const trs[8][8] = {
     { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
     { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
     { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
     { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65},
     { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
     { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
     { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
     { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, }
 };
</pre>

<p>
This is a two dimensional array of transparency values used in this demo. 
There are 8 rows, each for one 
state. Each of the 8 lines will continuosly use these values.
</p>

<pre class="explanation">
cairo_set_line_width(cr, 3);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
</pre>

<p>
We make the lines a bit thicker, so that they are better visible. 
We draw the lines with rouded caps.
</p>

<pre class="explanation">
cairo_set_source_rgba(cr, 0, 0, 0, trs[glob.count%8][i]);
</pre>

<p>
Here we define the transparency value for a line.
</p>

<pre class="explanation">
cairo_move_to(cr, 0.0, -10.0);
cairo_line_to(cr, 0.0, -40.0);
cairo_rotate(cr, M_PI/4);
</pre>

<p>
These code will draw each of the eight lines.
</p>

<pre class="explanation">
g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
</pre>

<p>
We use a timer function to create animation.
</p>


<img src="/img/gfx/cairoc/waiting.png" alt="Waiting demo">
<div class="figure">Figure: Waiting demo</div>


<p>
In this part of the Cairo tutorial, we have covered transparency. 
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified December 13, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

